package cc.rengu.igas.share.core.realize.impl;

import cc.rengu.chargecalc.mchntfee.CalcMchntFee;
import cc.rengu.chargecalc.mchntfee.model.CalcMchntFeeBean;
import cc.rengu.chargecalc.mchntfee.model.CalcMchntFeeResultBean;
import cc.rengu.chargecalc.mchntfee.model.CalcReverseMchntFeeBean;
import cc.rengu.chargecalc.mchntfee.model.CalcReverseMchntFeeResultBean;
import cc.rengu.igas.bomp.facade.base.Header;
import cc.rengu.igas.bomp.facade.bean.*;
import cc.rengu.igas.bomp.facade.request.*;
import cc.rengu.igas.bomp.facade.response.*;
import cc.rengu.igas.bomp.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.common.constant.ShareTreeNodeConstant;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.enums.MchntStatusEnum;
import cc.rengu.igas.share.common.enums.RespCodeEnum;
import cc.rengu.igas.share.core.model.*;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.jradp.asynnotify.AsynNotify;
import cc.rengu.oltp.service.common.constant.AppConfigConstant;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.MchntOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.MchntOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.TransLimitInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.TransLimitService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.service.realize.impl.TransLimitServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商户相关的业务实现组件
 *
 * @author wangcheng
 */
public class MchntServiceImpl implements MchntService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());
    private String callMode = "1";

    public MchntServiceImpl() throws Exception {
        String callMode = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.BOMP_SERVICE_CALL_MODE);
        if (!StringUtil.isEmptyOrNull(callMode)) {
            if (!"0".equals(callMode.trim()) && !"1".equals(callMode.trim())) {
                rglog.error("商户信息获取调用模式<{}>参数配置错误:0-本地调用，1-微服务调用!", callMode.trim());
                throw new BizException("商户信息获取方式配置有误:<{}>", callMode);
            } else {
                this.callMode = callMode.trim();
            }
        }
    }

    @Override
    public boolean checkPlatMchntStatus(String instId, String platMchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在校验平台商户<{}>信息,信息获取方式为<{}>", platMchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM024");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        PlatMchntListQueryRequest platMchntListQueryRequest = new PlatMchntListQueryRequest();
        platMchntListQueryRequest.setHeader(header);
        platMchntListQueryRequest.setPlatMchntNo(platMchntNo);
        platMchntListQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        platMchntListQueryRequest.setPageIndex(-1);
        platMchntListQueryRequest.setPageSize(-1);
        DubboService dubboService = new DubboServiceImpl();
        Result<PlatMchntListQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<PlatMchntListQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_PLAT_MCHNT_LIST_QUERY_METHOD, platMchntListQueryRequest);
        } else {
            callResult = (Result<PlatMchntListQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_PLAT_MCHNT_LIST_QUERY_METHOD, platMchntListQueryRequest);
        }
        if (null == callResult || null == callResult.getResult() || null == callResult.getResult().getPlatMchntInfoList() || callResult.getResult().getPlatMchntInfoList().isEmpty()) {
            rglog.error("获取平台商户信息失败，instId:<{}>,platMchnt:<{}>", instId, platMchntNo);
            return false;
        }
        PlatMchntInfoBean platMchntInfoBean = callResult.getResult().getPlatMchntInfoList().get(0);
        if (!MchntStatusEnum.NORMAL.getStatus().equals(platMchntInfoBean.getPlatMchntStatus())) {
            rglog.info("平台商户<{}>状态不正常:<{}>", platMchntNo, platMchntInfoBean.getPlatMchntStatus());
            return false;
        }
        PlatMchntInfo platMchntInfo = new PlatMchntInfo();
        platMchntInfo.setInstId(instId);
        BeanUtil.nullValueCopy(platMchntInfoBean, platMchntInfo);
        String platMchntInfoKey = TransCacheConstant.PLAT_MCHNT_INFO + "_" + platMchntInfo.getPlatMchntNo();
        GlobalTransUtil.setCacheValue(platMchntInfoKey, platMchntInfo);
        return true;
    }

    @Override
    public PlatMchntInfo getPlatMchntInfo(String instId, String platMchntNo) throws Exception {
        String platMchntInfoKey = TransCacheConstant.PLAT_MCHNT_INFO + "_" + platMchntNo;
        PlatMchntInfo platMchntInfo = (PlatMchntInfo) GlobalTransUtil.getCacheValue(platMchntInfoKey);
        if (null == platMchntInfo) {
            boolean checkResult = checkPlatMchntStatus(instId, platMchntNo);
            platMchntInfo = (PlatMchntInfo) GlobalTransUtil.getCacheValue(platMchntInfoKey);
            if (!checkResult || null == platMchntInfo) {
                rglog.error("平台商户状态异常或者平台商户<{}>不存在!", platMchntNo);
                return null;
            }
            /* 获取平台商户微信支付AppId等相关信息 */
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
            Header header = new Header();
            header.setInstId(instId);
            header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
            header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
            header.setTxnNum("M00BM048");
            header.setBizType("00");
            header.setVersion(ShareParamConstant.DUBBO_VSERSION);
            header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
            header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
            header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
            PlatMchntWechatInfoQueryRequest platMchntWechatInfoQueryRequest = new PlatMchntWechatInfoQueryRequest();
            platMchntWechatInfoQueryRequest.setHeader(header);
            platMchntWechatInfoQueryRequest.setPlatMchntNo(platMchntNo);
            platMchntWechatInfoQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
            DubboService dubboService = new DubboServiceImpl();
            Result<PlatMchntWechatInfoQueryResponse> callResult;
            if ("0".equals(callMode)) {
                Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
                callResult = (Result<PlatMchntWechatInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_PLAT_MCHNT_WECHAT_INFO_QUERY_METHOD, platMchntWechatInfoQueryRequest);
            } else {
                callResult = (Result<PlatMchntWechatInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_PLAT_MCHNT_WECHAT_INFO_QUERY_METHOD, platMchntWechatInfoQueryRequest);
            }
            if (null != callResult && null != callResult.getResult()) {
                PlatMchntWechatInfoQueryResponse platMchntWechatInfoQueryResponse = callResult.getResult();
                platMchntInfo.setWechatAppId(platMchntWechatInfoQueryResponse.getWechatAppid());
                platMchntInfo.setWechatAppIdKey(platMchntWechatInfoQueryResponse.getWechatAppidKey());
                platMchntInfo.setWechatMiniAppId(platMchntWechatInfoQueryResponse.getWechatMiniAppid());
                platMchntInfo.setWechatMiniAppIdKey(platMchntWechatInfoQueryResponse.getWechatMiniAppidKey());
                GlobalTransUtil.setCacheValue(platMchntInfoKey, platMchntInfo);
            }
        }
        return platMchntInfo;
    }

    @Override
    public boolean checkAgentMchntStatus(String instId, String agentMchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在校验代理商户<{}>信息,信息获取方式为<{}>", agentMchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM023");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        AgentMchntListQueryRequest agentMchntListQueryRequest = new AgentMchntListQueryRequest();
        agentMchntListQueryRequest.setHeader(header);
        agentMchntListQueryRequest.setAgentMchntNo(agentMchntNo);
        agentMchntListQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        agentMchntListQueryRequest.setPageIndex(-1);
        agentMchntListQueryRequest.setPageSize(-1);
        Result<AgentMchntListQueryResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<AgentMchntListQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_AGENT_MCHNT_LIST_QUERY_METHOD, agentMchntListQueryRequest);
        } else {
            callResult = (Result<AgentMchntListQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_AGENT_MCHNT_LIST_QUERY_METHOD, agentMchntListQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取代理商商户信息失败，instId:<{}>,platMchnt:<{}>", instId, agentMchntNo);
            return false;
        }
        AgentMchntListQueryResponse agentMchntListQueryResponse = callResult.getResult();
        if (!MchntStatusEnum.NORMAL.getStatus().equals(agentMchntListQueryResponse.getAgentMchntInfoList().get(0).getAgentMchntStatus())) {
            rglog.info("代理商商户<{}>状态不正常:<{}>", agentMchntNo, agentMchntListQueryResponse.getAgentMchntInfoList().get(0).getAgentMchntStatus());
            return false;
        }
        AgentMchntInfo agentMchntInfo = new AgentMchntInfo();
        BeanUtil.nullValueCopy(agentMchntListQueryResponse.getAgentMchntInfoList().get(0), agentMchntInfo);
        agentMchntInfo.setInstId(instId);
        String agentMchntInfoKey = TransCacheConstant.AGENT_MCHNT_INFO + "_" + agentMchntInfo.getAgentMchntNo();
        GlobalTransUtil.setCacheValue(agentMchntInfoKey, agentMchntInfo);
        return true;
    }

    @Override
    public AgentMchntInfo getAgentMchntInfo(String instId, String agentMchntNo) throws Exception {
        String agentMchntInfoKey = TransCacheConstant.AGENT_MCHNT_INFO + "_" + agentMchntNo;
        AgentMchntInfo agentMchntInfo = (AgentMchntInfo) GlobalTransUtil.getCacheValue(agentMchntInfoKey);
        if (null == agentMchntInfo) {
            boolean checkResult = checkAgentMchntStatus(instId, agentMchntNo);
            agentMchntInfo = (AgentMchntInfo) GlobalTransUtil.getCacheValue(agentMchntInfoKey);
            if (!checkResult || null == agentMchntInfo) {
                rglog.error("代理商商户状态异常或者代理商商户<{}>不存在!", agentMchntNo);
                return null;
            }
        }
        return agentMchntInfo;
    }

    @Override
    public boolean checkGroupMchntStatus(String instId, String groupMchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在校验集团商户<{}>信息,信息获取方式为<{}>", groupMchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM025");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        GroupMchntListQueryRequest groupMchntListQueryRequest = new GroupMchntListQueryRequest();
        groupMchntListQueryRequest.setHeader(header);
        groupMchntListQueryRequest.setGroupMchntNo(groupMchntNo);
        groupMchntListQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        groupMchntListQueryRequest.setPageIndex(-1);
        groupMchntListQueryRequest.setPageSize(-1);
        Result<GroupMchntListQueryResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<GroupMchntListQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_GROUP_MCHNT_LIST_QUERY_METHOD, groupMchntListQueryRequest);
        } else {
            callResult = (Result<GroupMchntListQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_GROUP_MCHNT_LIST_QUERY_METHOD, groupMchntListQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取集团商商户信息失败，instId:<{}>,platMchnt:<{}>", instId, groupMchntNo);
            return false;
        }
        GroupMchntListQueryResponse groupMchntListQueryResponse = callResult.getResult();
        if (!MchntStatusEnum.NORMAL.getStatus().equals(groupMchntListQueryResponse.getGroupMchntInfoList().get(0).getGroupMchntStatus())) {
            rglog.info("集团商商户<{}>状态不正常:<{}>", groupMchntNo, groupMchntListQueryResponse.getGroupMchntInfoList().get(0).getGroupMchntStatus());
            return false;
        }
        GroupMchntInfo groupMchntInfo = new GroupMchntInfo();
        BeanUtil.nullValueCopy(groupMchntListQueryResponse.getGroupMchntInfoList().get(0), groupMchntInfo);
        groupMchntInfo.setInstId(instId);
        String groupMchntInfoKey = TransCacheConstant.GROUP_MCHNT_INFO + "_" + groupMchntInfo.getGroupMchntNo();
        GlobalTransUtil.setCacheValue(groupMchntInfoKey, groupMchntInfo);
        return true;
    }

    @Override
    public GroupMchntInfo getGroupMchntInfo(String instId, String groupMchntNo) throws Exception {
        String groupMchntInfoKey = TransCacheConstant.GROUP_MCHNT_INFO + "_" + groupMchntNo;
        GroupMchntInfo groupMchntInfo = (GroupMchntInfo) GlobalTransUtil.getCacheValue(groupMchntInfoKey);
        if (null == groupMchntInfo) {
            boolean checkResult = checkGroupMchntStatus(instId, groupMchntNo);
            groupMchntInfo = (GroupMchntInfo) GlobalTransUtil.getCacheValue(groupMchntInfoKey);
            if (!checkResult || null == groupMchntInfo) {
                rglog.error("集团商商户状态异常或者集团商商户<{}>不存在!", groupMchntNo);
                return null;
            }
        }
        return groupMchntInfo;
    }

    @Override
    public boolean checkMchntStatus(String instId, String mchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在校验商户<{}>信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM005");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntBaseInfoQueryRequest mchntBaseInfoQueryRequest = new MchntBaseInfoQueryRequest();
        mchntBaseInfoQueryRequest.setHeader(header);
        mchntBaseInfoQueryRequest.setMchntNo(mchntNo);
        mchntBaseInfoQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntBaseInfoQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntBaseInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_BASE_INFO_QUERY_METHOD, mchntBaseInfoQueryRequest);
        } else {
            callResult = (Result<MchntBaseInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_BASE_INFO_QUERY_METHOD, mchntBaseInfoQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取商户信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return false;
        }
        MchntBaseInfoQueryResponse mchntBaseInfoQueryResponse = callResult.getResult();
        /*商户基本信息表存在但商户状态不正确*/
        if (!MchntStatusEnum.NORMAL.getStatus().equals(mchntBaseInfoQueryResponse.getMchntStatus())) {
            rglog.info("商户<{}>状态不正常:<{}>", mchntNo, mchntBaseInfoQueryResponse.getMchntStatus());
            return false;
        }
        /* 将商户信息放到交易缓存中 */
        MchntInfo mchntInfo = new MchntInfo();
        BeanUtil.nullValueCopy(mchntBaseInfoQueryResponse.getMchntBaseInfo(), mchntInfo);
        BeanUtil.nullValueCopy(mchntBaseInfoQueryResponse.getMchntContactsInfo(), mchntInfo);
        BeanUtil.nullValueCopy(mchntBaseInfoQueryResponse.getWechatMchntInfo(), mchntInfo);
        mchntInfo.setInstId(instId);
        mchntInfo.setWechatMchntNo(mchntBaseInfoQueryResponse.getWechatMchntInfo().getWechatMchntNo());
        mchntInfo.setWechatChannelType(mchntBaseInfoQueryResponse.getWechatMchntInfo().getDstChannelType());
        mchntInfo.setAlipayMchntNo(mchntBaseInfoQueryResponse.getAlipayMchntInfo().getAlipayMchntNo());
        mchntInfo.setAlipayChannelType(mchntBaseInfoQueryResponse.getAlipayMchntInfo().getDstChannelType());
        mchntInfo.setAlipayBatchNo(mchntBaseInfoQueryResponse.getAlipayMchntInfo().getBatchNo());
        mchntInfo.setAlipayAppAuthToken(mchntBaseInfoQueryResponse.getAlipayMchntInfo().getAppAuthToken());
        mchntInfo.setCupsMchntNo(mchntBaseInfoQueryResponse.getCupsMchntInfo().getCupsMchntNo());
        mchntInfo.setSpecialBillingType(mchntBaseInfoQueryResponse.getCupsMchntInfo().getSpecialBillingType());
        mchntInfo.setCupsChannelMchntNo(mchntBaseInfoQueryResponse.getCupsMchntInfo().getCupsChannelMchntNo());
        mchntInfo.setCupsInstId(mchntBaseInfoQueryResponse.getCupsMchntInfo().getCupsInstCode());
        mchntInfo.setCupsAreaCode(mchntBaseInfoQueryResponse.getCupsMchntInfo().getCupsAreaCode());
        mchntInfo.setSmsSendFlag(mchntBaseInfoQueryResponse.getMchntBaseInfo().getSmsFlag());
        mchntInfo.setMchntStatus(mchntBaseInfoQueryResponse.getMchntStatus());
        String mchntInfoKey = TransCacheConstant.MCHNT_INFO + "_" + mchntNo;
        GlobalTransUtil.setCacheValue(mchntInfoKey, mchntInfo);
        return true;
    }

    @Override
    public MchntInfo getMchntInfo(String instId, String mchntNo) throws Exception {
        String mchntInfoKey = TransCacheConstant.MCHNT_INFO + "_" + mchntNo;
        MchntInfo mchntInfo = (MchntInfo) GlobalTransUtil.getCacheValue(mchntInfoKey);
        if (null == mchntInfo) {
            boolean checkResult = checkMchntStatus(instId, mchntNo);
            mchntInfo = (MchntInfo) GlobalTransUtil.getCacheValue(mchntInfoKey);
            if (!checkResult || null == mchntInfo) {
                rglog.error("商户状态异常或者平台商户<{}>不存在!", mchntNo);
                return null;
            }
        }
        return mchntInfo;
    }

    @Override
    public MchntInfo getMchntSignInfo(String instId, String mchntNo) throws Exception {
        String mchntInfoKey = TransCacheConstant.MCHNT_INFO + "_" + mchntNo;
        MchntInfo mchntInfo = (MchntInfo) GlobalTransUtil.getCacheValue(mchntInfoKey);
        if (null == mchntInfo) {
            boolean checkResult = checkMchntStatus(instId, mchntNo);
            mchntInfo = (MchntInfo) GlobalTransUtil.getCacheValue(mchntInfoKey);
            if (!checkResult || null == mchntInfo) {
                rglog.error("商户状态异常或者平台商户<{}>不存在!", mchntNo);
                return null;
            }
        }
        rglog.info("正在获取商户<{}>的签约信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM006");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntSignInfoQueryRequest mchntBaseInfoQueryRequest = new MchntSignInfoQueryRequest();
        mchntBaseInfoQueryRequest.setHeader(header);
        mchntBaseInfoQueryRequest.setMchntNo(mchntNo);
        mchntBaseInfoQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntSignInfoQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntSignInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_SIGN_INFO_QUERY_METHOD, mchntBaseInfoQueryRequest);
        } else {
            callResult = (Result<MchntSignInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_SIGN_INFO_QUERY_METHOD, mchntBaseInfoQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取商户签约信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        BeanUtil.nullValueCopy(callResult.getResult().getBusinessLicenceInfo(), mchntInfo);
        BeanUtil.nullValueCopy(callResult.getResult().getMchntArtifInfo(), mchntInfo);
        return mchntInfo;
    }

    @Override
    public List<MchntAuthInfo> getMchntAuthInfo(String instId, String mchntNo, String termNo) throws Exception {
        return getMchntAuthInfo(instId, mchntNo, termNo, null, null);
    }

    @Override
    public List<MchntAuthInfo> getMchntAuthInfo(String instId, String mchntNo, String termNo, String txnNum, String bizType) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>或终端<{}>的权业务权限控制信息,信息获取方式为<{}>", mchntNo, termNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM052");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntTxnAuthQueryRequest mchntTxnAuthQueryRequest = new MchntTxnAuthQueryRequest();
        mchntTxnAuthQueryRequest.setHeader(header);
        mchntTxnAuthQueryRequest.setCtrlType(StringUtil.isEmptyOrNull(termNo) ? "MCHNT" : "TERM");
        mchntTxnAuthQueryRequest.setTxnNum(txnNum);
        mchntTxnAuthQueryRequest.setBizType(bizType);
        MchntInfo mchntInfo = getMchntInfo(instId, mchntNo);
        /* 非独立清算的门店商户使用连锁商户号进行权限验证 */
        if (null != mchntInfo && "11".equals(mchntInfo.getMchntType()) && AppParamConstant.NO.equals(mchntInfo.getIndependentDataFlag())) {
            mchntTxnAuthQueryRequest.setMchntNo(mchntInfo.getChainMchntNo());
        } else {
            mchntTxnAuthQueryRequest.setMchntNo(mchntNo);
        }
        mchntTxnAuthQueryRequest.setTermNo(StringUtil.isEmptyOrNull(termNo) ? "*" : termNo);
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntTxnAuthQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntTxnAuthQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_TXN_AUTH_QUERY_METHOD, mchntTxnAuthQueryRequest);
        } else {
            callResult = (Result<MchntTxnAuthQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_TXN_AUTH_QUERY_METHOD, mchntTxnAuthQueryRequest);
        }
        if (null == callResult || null == callResult.getResult() || null == callResult.getResult().getMchntAuthCtrlInfoList()) {
            rglog.error("获取商户或终端交易权限配置失败，mchntNo:<{}>,termNo:<{}>", mchntNo, termNo);
            return null;
        }
        List<MchntAuthInfo> mchntAuthInfoList = new ArrayList<>();
        List<MchntAuthCtrlInfoBean> mchntAuthCtrlInfoBeanList = callResult.getResult().getMchntAuthCtrlInfoList();
        for (MchntAuthCtrlInfoBean mchntAuthCtrlInfoBean : mchntAuthCtrlInfoBeanList) {
            MchntAuthInfo mchntAuthInfo = new MchntAuthInfo();
            BeanUtil.beanCopy(mchntAuthCtrlInfoBean, mchntAuthInfo);
            mchntAuthInfoList.add(mchntAuthInfo);
        }
        return mchntAuthInfoList;
    }

    @Override
    public boolean checkMchntAuth(String instId, String mchntNo, String termNo, String txnNum, String bizType, String acctType) throws Exception {
        rglog.info("正在校验商户权限信息!");
        if (TransTypeEnum.MANAGE.equals(TransTypeEnum.getTransType(txnNum))) {
            rglog.info("管理类交易默认都有权限，不进行权限控制!");
            return true;
        }
        List<MchntAuthInfo> mchntAuthInfoList = getMchntAuthInfo(instId, mchntNo, termNo, txnNum, bizType);
        if (null == mchntAuthInfoList || mchntAuthInfoList.isEmpty()) {
            rglog.info("当前商户<{}>或者终端<{}>未配置权限!", mchntNo, termNo);
            return false;
        }
        MchntAuthInfo mchntAuthInfo = mchntAuthInfoList.get(0);
        if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportFlag())) {
            rglog.error("商户不支持该交易类型，instId:<{}>,ctrlType:<{}>,mchntNo:<{}>,termNo:<{}>,bizType:<{}>");
            return false;
        }
        /*检查支持的账户类型*/
        if (AcctTypeEnum.ALL.getAcctType().equals(mchntAuthInfo.getSupportAcctType()) || AcctTypeEnum.ALL.getAcctType().equals(acctType)) {
            rglog.info("商户当前交易支持所有账户类型,mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", mchntNo, termNo, txnNum, bizType);
            return true;
        } else if (AcctTypeEnum.BANK_DEBIT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(0, 1))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.BANK_DEBIT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.BANK_CREDIT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(1, 2))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.BANK_CREDIT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.BANK_PASSBOOK.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(2, 3))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.BANK_PASSBOOK.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.BANK_ACCT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(3, 4))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.BANK_ACCT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
            return true;
        } else if (AcctTypeEnum.BANK_PUB_ACCT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(4, 5))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.BANK_PUB_ACCT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(5, 6))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.OTHER_DEBIT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.OTHER_CREDIT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(6, 7))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.OTHER_CREDIT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.OTHER_PASSBOOK.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(7, 8))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.OTHER_PASSBOOK.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.OTHER_ACCT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(8, 9))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.OTHER_ACCT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else if (AcctTypeEnum.OTHER_PUB_ACCT.getAcctType().equals(acctType)) {
            if (AppParamConstant.NO.equals(mchntAuthInfo.getSupportAcctType().substring(9, 10))) {
                rglog.error("商户当前交易不支持{},mchntNo:<{}>,termNo:<{}>,txnNum:<{}>,bizType:<{}>", AcctTypeEnum.OTHER_PUB_ACCT.getAcctDesc(), mchntNo, termNo, txnNum, bizType);
                return false;
            }
        } else {
            rglog.error("未知的账户类型<{}>", acctType);
            return false;
        }
        return true;
    }

    @Override
    public List<TransLimitInfo> getMchntTransLimitInfo(String instId, String mchntNo, String termNo, String txnNum) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>或终端<{}>的交易限额,信息获取方式为<{}>", mchntNo, termNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM053");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntTxnLimitCfgQueryRequest mchntTxnLimitCfgQueryRequest = new MchntTxnLimitCfgQueryRequest();
        mchntTxnLimitCfgQueryRequest.setHeader(header);
        mchntTxnLimitCfgQueryRequest.setMchntNo(mchntNo);
        mchntTxnLimitCfgQueryRequest.setTermNo(termNo);
        mchntTxnLimitCfgQueryRequest.setTxnNum(txnNum);
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntTxnLimitCfgQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntTxnLimitCfgQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_TXN_LIMIT_CFG_QUERY_METHOD, mchntTxnLimitCfgQueryRequest);
        } else {
            callResult = (Result<MchntTxnLimitCfgQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_TXN_LIMIT_CFG_QUERY_METHOD, mchntTxnLimitCfgQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("商户未配置交易限额配置信息，不进行限额控制，mchntNo:<{}>,termNo:<{}>,txnNum:<{}>", mchntNo, termNo, txnNum);
            return null;
        }
        /* 商户限额检查，维度从小到大逐级控制，以最小维度的限额进行控制 */
        MchntTxnLimitCfgQueryResponse mchntTxnLimitCfgQueryResponse = callResult.getResult();
        List<TransLimitInfo> transLimitInfoList = new ArrayList<>();
        List<TxnLimitCfgBean> txnLimitCfgBeanList = new ArrayList<>();
        if (TransTypeEnum.REFUND.equals(TransTypeEnum.getTransType(txnNum))) {
            if (null != mchntTxnLimitCfgQueryResponse.getMchntRefundLimitList() && !mchntTxnLimitCfgQueryResponse.getMchntRefundLimitList().isEmpty()) {
                /* 退款限额 */
                txnLimitCfgBeanList = mchntTxnLimitCfgQueryResponse.getMchntRefundLimitList();
            }
        } else {
            if (null != mchntTxnLimitCfgQueryResponse.getTransLimitList() && !mchntTxnLimitCfgQueryResponse.getTransLimitList().isEmpty()) {
                /* 交易限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getTransLimitList());
            }
            if (null != mchntTxnLimitCfgQueryResponse.getTermLimitList() && !mchntTxnLimitCfgQueryResponse.getTermLimitList().isEmpty()) {
                /* 终端限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getTermLimitList());
            }
            if (null != mchntTxnLimitCfgQueryResponse.getMchntLimitList() && !mchntTxnLimitCfgQueryResponse.getMchntLimitList().isEmpty()) {
                /* 商户限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getMchntLimitList());
            }
            if (null != mchntTxnLimitCfgQueryResponse.getMchntLevelLimitList() && !mchntTxnLimitCfgQueryResponse.getMchntLevelLimitList().isEmpty()) {
                /* 商户等级限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getMchntLevelLimitList());
            }
            if (null != mchntTxnLimitCfgQueryResponse.getMchntMccLimitList() && !mchntTxnLimitCfgQueryResponse.getMchntMccLimitList().isEmpty()) {
                /* 行业类型限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getMchntMccLimitList());
            }
            if (null != mchntTxnLimitCfgQueryResponse.getMchntScopeLimitList() && !mchntTxnLimitCfgQueryResponse.getMchntScopeLimitList().isEmpty()) {
                /* 行业级别限额 */
                txnLimitCfgBeanList.addAll(mchntTxnLimitCfgQueryResponse.getMchntScopeLimitList());
            }
        }
        if (null != txnLimitCfgBeanList && !txnLimitCfgBeanList.isEmpty()) {
            txnLimitCfgBeanList = txnLimitCfgBeanList.stream().sorted(Comparator.comparing(TxnLimitCfgBean::getLimitAcctType)).collect(Collectors.toList());
            for (TxnLimitCfgBean txnLimitCfg : txnLimitCfgBeanList) {
                TransLimitInfo transLimitInfo = new TransLimitInfo();
                BeanUtil.beanCopy(txnLimitCfg, transLimitInfo);
                transLimitInfoList.add(transLimitInfo);
            }
        }
        return transLimitInfoList;
    }

    @Override
    public int checkMchntTransLimit(String instId, String transAmt, LimitAcctTypeEnum limitAcctType, String mchntNo, String termNo, String txnNum) throws Exception {
        rglog.info("正在进行商户限额检查!");
        List<TransLimitInfo> transLimitInfoList = getMchntTransLimitInfo(instId,mchntNo,termNo,txnNum);
        if (null != transLimitInfoList && !transLimitInfoList.isEmpty()) {
            TransLimitService transLimitService = new TransLimitServiceImpl(instId, txnNum, null);
            /* 商户借贷记限额检查 */
            List<TransLimitInfo> transLimitInfos = transLimitInfoList.stream().filter(item -> item.getLimitAcctType().equals(limitAcctType.getAcctType())).collect(Collectors.toList());
            if (!transLimitInfos.isEmpty() && !transLimitService.transLimitCheck(transAmt, transLimitInfos)) {
                if (limitAcctType.equals(LimitAcctTypeEnum.BANK_CREDIT) || limitAcctType.equals(LimitAcctTypeEnum.OTHER_CREDIT) || limitAcctType.equals(LimitAcctTypeEnum.CREDIT)) {
                    rglog.error("商户贷记限额检查不通过,mchntNo:<{}>", mchntNo);
                    return 1;
                } else if (limitAcctType.equals(LimitAcctTypeEnum.BANK_DEBIT) || limitAcctType.equals(LimitAcctTypeEnum.BANK_PASSBOOK) || limitAcctType.equals(LimitAcctTypeEnum.BANK_ACCT) ||
                        limitAcctType.equals(LimitAcctTypeEnum.BANK_PUB_ACCT) || limitAcctType.equals(LimitAcctTypeEnum.OTHER_DEBIT) || limitAcctType.equals(LimitAcctTypeEnum.OTHER_PASSBOOK) ||
                        limitAcctType.equals(LimitAcctTypeEnum.OTHER_ACCT) || limitAcctType.equals(LimitAcctTypeEnum.OTHER_PUB_ACCT) || limitAcctType.equals(LimitAcctTypeEnum.DEBIT)) {
                    rglog.error("商户借记限额检查不通过,mchntNo:<{}>", mchntNo);
                    return 2;
                } else if (limitAcctType.equals(LimitAcctTypeEnum.ALL)) {
                    rglog.error("商户累计限额检查不通过,mchntNo:<{}>", mchntNo);
                    return 3;
                }
            }
            /* 将商户交易限额信息放到交易缓存中,在更新商户累计限额时使用当前存入的数据进行更新 */
            TransLimitBean transLimitBean = new TransLimitBean();
            transLimitBean.setLimitInst(mchntNo);
            transLimitBean.setOrderAmt(transAmt);
            transLimitBean.setTransLimitInfoList(transLimitInfoList);
            GlobalTransUtil.setCacheValue(TransCacheConstant.MCHNT_TRANS_LIMIT_INFO_LIST, transLimitBean);
        }
        return 0;
    }

    @Override
    public void updateMchntTransLimit(List<MchntOrderInfo> mchntOrderInfoList) throws Exception {
        rglog.info("正在更新商户限额统计信息!");
        if ("00".equals(mchntOrderInfoList.get(0).getBizSceneType())
                || "01".equals(mchntOrderInfoList.get(0).getBizSceneType())
                || "02".equals(mchntOrderInfoList.get(0).getBizSceneType())) {
            rglog.info("购买卡券交易或担保支付的交易,bizSceneType:<{}>，不累计商户限额。担保支付确认之后再累计", mchntOrderInfoList.get(0).getBizSceneType());
            return;
        }
        TransLimitBean transLimitBean = (TransLimitBean) GlobalTransUtil.getCacheValue(TransCacheConstant.MCHNT_TRANS_LIMIT_INFO_LIST);
        if (null != transLimitBean && !transLimitBean.getTransLimitInfoList().isEmpty()) {
            rglog.debug("更新商户限额数据:<{}>", JSON.toJSONString(transLimitBean.getTransLimitInfoList()));
            rglog.debug("累计更新的金额:<{}>", transLimitBean.getOrderAmt());
            String instId = mchntOrderInfoList.get(0).getInstId();
            String txnNum = mchntOrderInfoList.get(0).getTxnNum();
            TransLimitService transLimitService = new TransLimitServiceImpl(instId, txnNum, null);
            if (!transLimitService.transLimitStatis(transLimitBean.getOrderAmt(), transLimitBean.getTransLimitInfoList())) {
                rglog.error("更新商户限额累计失败！");
            }
        } else {
            rglog.error("无法从交易缓存中获取商户交易限额信息!");
        }
    }

    @Override
    public void updateMchntTransLimit(MchntOrderInfo mchntOrderInfo) {
        rglog.info("正在更新商户<{}>限额统计信息!", mchntOrderInfo.getMchntNo());
        if ("00".equals(mchntOrderInfo.getBizSceneType())
                || "01".equals(mchntOrderInfo.getBizSceneType())
                || "02".equals(mchntOrderInfo.getBizSceneType())) {
            rglog.info("购买卡券交易或担保支付的交易,bizSceneType:<{}>，不累计商户限额。担保支付确认之后再累计", mchntOrderInfo.getBizSceneType());
            return;
        }
        TransLimitBean transLimitBean = (TransLimitBean) GlobalTransUtil.getCacheValue(TransCacheConstant.MCHNT_TRANS_LIMIT_INFO_LIST);
        if (null != transLimitBean && !transLimitBean.getTransLimitInfoList().isEmpty()) {
            rglog.debug("更新商户限额数据:<{}>", JSON.toJSONString(transLimitBean.getTransLimitInfoList()));
            AsynNotify asynNotify = new AsynNotify();
            int iReturnCode = asynNotify.transactionNotice("AsynShareTransLimitStatisService", 1, 0, 0);
            if (0 != iReturnCode) {
                rglog.error("异步调用服务<AsynShareTransLimitStatisService>注册失败,iReturnCode:<{}>", iReturnCode);
            } else {
                rglog.debug("异步调用服务<AsynShareTransLimitStatisService>注册成功,iReturnCode:<{}>", iReturnCode);
            }
        } else {
            rglog.error("无法从交易缓存中获取商户交易限额信息!");
        }
    }

    @Override
    public boolean checkMchntRefundLimit(String instId, String mchntNo, String refundAmt) throws Exception {
        rglog.info("正在校验商户<{}>的退款限额,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        String transDate = DateUtil.getCurrentDate();
        String payTotalAmt = "0";
        String refundTotalAmt = "0";
        //未确认收货退款累计金额
        String notConfirmRefundAmt = "0";
        //卡券购买累计退款金额
        String couponRefundAmt = "0";
        MchntOrderInfoMapper mchntOrderInfoMapper = new MchntOrderInfoMapperImpl();
        List<StatisTransAmt> statisTransAmtList = mchntOrderInfoMapper.statisMchntTransAmtByTransType(instId, mchntNo, transDate);
        if (statisTransAmtList == null || statisTransAmtList.isEmpty()) {
            rglog.error("商户<{}>当天<{}>未发生收款交易，不允许退款", mchntNo, transDate);
            return false;
        }
        rglog.debug("statisTransAmtList=[{}]", JSON.toJSONString(statisTransAmtList));
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        for (StatisTransAmt statisTransAmt : statisTransAmtList) {
            if (xmlTreeUtil.isExist(ShareTreeNodeConstant.CHAIN_MCHNT_ORDER_FLAG)
                    && AppParamConstant.YES.equals(xmlTreeUtil.getXmlTreeStringValue(ShareTreeNodeConstant.CHAIN_MCHNT_ORDER_FLAG))) {
                rglog.info("非独立清算的门店商户发起退款通过连锁商户号获取商户订单，需要过滤该连锁商户下独立清算的门店商户所发生的订单");
                String mchntInfoKey = TransCacheConstant.MCHNT_INFO + "_" + mchntNo;
                MchntInfo mchntInfo = (MchntInfo) GlobalTransUtil.getCacheValue(mchntInfoKey);
                if (null != mchntInfo && "11".equals(mchntInfo.getMchntType()) && AppParamConstant.YES.equals(mchntInfo.getIndependentDataFlag())) {
                    rglog.info("退款交易时中独立维护资料的门店商户:<{}>在校验连锁商户当日支付交易是否大于退款交易时，该商户的交易不纳入统计数据");
                    continue;
                }
            }
            if (TransTypeEnum.PAY.getTransType().equals(statisTransAmt.getTransType()) &&
                    (BizStatusEnum.NOT_CONFIRM_PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.NOT_CONFIRM_REFUND.getStatus().equals(statisTransAmt.getBizStatus()))) {
                notConfirmRefundAmt = AmountUtil.addition(notConfirmRefundAmt, statisTransAmt.getTotalRefundAmt());
            } else if (TransTypeEnum.PAY.getTransType().equals(statisTransAmt.getTransType()) && "01".equals(statisTransAmt.getBizSceneType()) &&
                    (BizStatusEnum.CONFIRM.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus()))) {
                payTotalAmt = AmountUtil.addition(payTotalAmt, statisTransAmt.getTotalOrderAmt());
            } else if (("01".equals(statisTransAmt.getTransType()) || "06".equals(statisTransAmt.getTransType())) &&
                    (BizStatusEnum.FINISH.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.COUPON_REDEEM.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus())) &&
                    !"01".equals(statisTransAmt.getBizSceneType())) {
                if ("00".equals(statisTransAmt.getBizSceneType()) || "02".equals(statisTransAmt.getBizSceneType())) {
                    if (BizStatusEnum.REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus())) {
                        /*累计购买卡券退款金额*/
                        couponRefundAmt = AmountUtil.addition(couponRefundAmt, statisTransAmt.getTotalRefundAmt());
                    } else if (BizStatusEnum.COUPON_REDEEM.getStatus().equals(statisTransAmt.getBizStatus())) {
                        /*累计卡券购买已核销的支付金额*/
                        payTotalAmt = AmountUtil.addition(payTotalAmt, statisTransAmt.getTotalOrderAmt());
                    }
                } else {
                    /*支付成功金额*/
                    payTotalAmt = AmountUtil.addition(payTotalAmt, statisTransAmt.getTotalOrderAmt());
                }
            } else if ("04".equals(statisTransAmt.getTransType()) &&
                    (BizStatusEnum.FINISH.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.PROCESSING.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.NOT_CONFIRM_REFUND.getStatus().equals(statisTransAmt.getBizStatus()) ||
                            BizStatusEnum.NOT_CONFIRM_PART_REFUND.getStatus().equals(statisTransAmt.getBizStatus()))) {
                refundTotalAmt = AmountUtil.addition(refundTotalAmt, statisTransAmt.getTotalOrderAmt());
            }
        }
        /*减去未确认收货的退款金额*/
        rglog.info("未确认收货的退款金额：[{}]", notConfirmRefundAmt);
        refundAmt = AmountUtil.subtraction(refundAmt, notConfirmRefundAmt);
        /*减去卡券购买未核销的退款金额*/
        rglog.info("卡券购买未核销的退款金额：[{}]", couponRefundAmt);
        refundAmt = AmountUtil.subtraction(refundAmt, couponRefundAmt);
        /*统计交易信息*/
        rglog.info("商户<{}>当天成功支付总金额<{}>,当天累计退款金额<{}>,本次退款金额<{}>", mchntNo, payTotalAmt, refundTotalAmt, refundAmt);
        if (AmountUtil.compare(payTotalAmt, AmountUtil.addition(refundTotalAmt, refundAmt)) == -1) {
            rglog.error("商户<{}>当天成功支付总金额<{}>小于当天累计退款金额<{}>+本次退款金额<{}>，不允许退款", mchntNo, payTotalAmt, refundTotalAmt, refundAmt);
            return false;
        }
        return true;
    }

    @Override
    public List<MchntProdInfo> getMchntProdInfo(String instId, String mchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>的产品权限信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM009");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntProdListQueryRequest mchntProdListQueryRequest = new MchntProdListQueryRequest();
        mchntProdListQueryRequest.setHeader(header);
        mchntProdListQueryRequest.setMchntNo(mchntNo);
        mchntProdListQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntProdListQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntProdListQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_PROD_LIST_QUERY_METHOD, mchntProdListQueryRequest);
        } else {
            callResult = (Result<MchntProdListQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_PROD_LIST_QUERY_METHOD, mchntProdListQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取商户产品列表信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        List<MchntProdInfo> mchntProdInfoList = new ArrayList<>();
        for (MchntProdInfoBean mchntProdInfoBean : callResult.getResult().getMchntProdInfoList()) {
            MchntProdInfo mchntProdInfo = new MchntProdInfo();
            BeanUtil.beanCopy(mchntProdInfoBean, mchntProdInfo);
            mchntProdInfoList.add(mchntProdInfo);
        }
        return mchntProdInfoList;
    }

    @Override
    public List<MchntStageInfo> getMchntStageInfo(String instId, String mchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>的分期产品权限信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM010");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntProdInfoQueryRequest mchntProdInfoQueryRequest = new MchntProdInfoQueryRequest();
        mchntProdInfoQueryRequest.setMchntNo(mchntNo);
        mchntProdInfoQueryRequest.setBaseProdCode(BaseProdEnum.STAGE_PAY.getProdCode()); /* 分期产品 */
        mchntProdInfoQueryRequest.setUserId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID));
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntProdInfoQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntProdInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_PROD_INFO_QUERY_METHOD, mchntProdInfoQueryRequest);
        } else {
            callResult = (Result<MchntProdInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_PROD_INFO_QUERY_METHOD, mchntProdInfoQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取商户分期产品信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        List<MchntStageInfo> mchntStageInfoList = new ArrayList<>();
        for (MchntStageInfoBean mchntStageInfoBean : callResult.getResult().getMchntStageInfoList()) {
            if (AppParamConstant.YES.equals(mchntStageInfoBean.getRecordStatus())) {
                MchntStageInfo mchntStageInfo = new MchntStageInfo();
                BeanUtil.beanCopy(mchntStageInfoBean, mchntStageInfo);
                mchntStageInfoList.add(mchntStageInfo);
            }
        }
        return mchntStageInfoList;
    }

    @Override
    public List<MchntAcctInfo> getMchntAcctInfo(String instId, String mchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>的结算账户信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        /* 从交易缓存中获取商户信息 */
        MchntInfo mchntInfo = getMchntInfo(instId, mchntNo);
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        /* 获取商户费率信息，特殊计费商户不支持商户实时入账 */
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM007");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        /* 获取商户结算账户信息，判断商户是否配置的为D0实时清算 */
        MchntSettleAcctInfoQueryRequest mchntSettleAcctInfoQueryRequest = new MchntSettleAcctInfoQueryRequest();
        mchntSettleAcctInfoQueryRequest.setHeader(header);
        mchntSettleAcctInfoQueryRequest.setUserId(instId);
        if (("11".equals(mchntInfo.getMchntType())) && AppParamConstant.NO.equals(mchntInfo.getIndependentDataFlag())) {
            rglog.debug("商户为非独立清算的门店商户，以连锁商户号:<{}>进行判断是否实时清算", mchntInfo.getChainMchntNo());
            mchntSettleAcctInfoQueryRequest.setMchntNo(mchntInfo.getChainMchntNo());
        } else {
            mchntSettleAcctInfoQueryRequest.setMchntNo(mchntNo);
        }
        Result<MchntSettleAcctInfoQueryResponse> mchntSettleAcctInfoCallResult;
        DubboService dubboService = new DubboServiceImpl();
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            mchntSettleAcctInfoCallResult = (Result<MchntSettleAcctInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_SETTLE_ACCT_QUERY_METHOD, mchntSettleAcctInfoQueryRequest);
        } else {
            mchntSettleAcctInfoCallResult = (Result<MchntSettleAcctInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_SETTLE_ACCT_QUERY_METHOD, mchntSettleAcctInfoQueryRequest);
        }
        if (null == mchntSettleAcctInfoCallResult || null == mchntSettleAcctInfoCallResult.getResult()) {
            rglog.error("获取商户结算账户信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        MchntSettleAcctInfoQueryResponse mchntSettleAcctInfoQueryResponse = mchntSettleAcctInfoCallResult.getResult();
        List<MchntAcctInfo> mchntAcctInfoList = new ArrayList<>();
        for (SettleAcctInfoBean mchntSettleInfoBean : mchntSettleAcctInfoQueryResponse.getSettleAcctInfoList()) {
            MchntAcctInfo mchntAcctInfo = new MchntAcctInfo();
            BeanUtil.beanCopy(mchntSettleInfoBean, mchntAcctInfo);
            mchntAcctInfoList.add(mchntAcctInfo);
        }
        return mchntAcctInfoList;
    }

    @Override
    public List<MchntFeeInfo> getMchntFeeInfo(String instId, String mchntNo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>的手续费配置信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        /* 获取商户费率信息，特殊计费商户不支持商户实时入账 */
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM050");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntFeeListQueryRequest mchntFeeListQueryRequest = new MchntFeeListQueryRequest();
        mchntFeeListQueryRequest.setHeader(header);
        mchntFeeListQueryRequest.setMchntNo(mchntNo);
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntFeeListQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntFeeListQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_FEE_LIST_QUERY_METHOD, mchntFeeListQueryRequest);
        } else {
            callResult = (Result<MchntFeeListQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_FEE_LIST_QUERY_METHOD, mchntFeeListQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.error("获取商户费率信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return null;
        }
        List<MchntFeeInfo> mchntFeeInfoList = new ArrayList<>();
        MchntFeeListQueryResponse mchntFeeListQueryResponse = callResult.getResult();
        for (MchntFeeInfoBean mchntFeeInfoBean : mchntFeeListQueryResponse.getMchntFeeInfoBeanList()) {
            MchntFeeInfo mchntFeeInfo = new MchntFeeInfo();
            BeanUtil.beanCopy(mchntFeeInfoBean, mchntFeeInfo);
            mchntFeeInfoList.add(mchntFeeInfo);
        }
        return mchntFeeInfoList;
    }

    @Override
    public String getRealSettleFlag(String mchntNo, String bizProdCode, String bizScene, String realSettleAmt) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        /* 从交易缓存中获取商户信息 */
        MchntInfo mchntInfo = getMchntInfo(instId, mchntNo);
        if (null == mchntInfo) {
            rglog.error("入参商户基本信息为空,不实时清算");
            rglog.error("获取商户信息失败，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return AppParamConstant.NO;
        }
        /* 担保支付及购买卡卷等场景不支持商户实时清算 */
        if ("00".equals(bizScene) || "01".equals(bizScene) || "02".equals(bizScene)) {
            rglog.info("商户订单为购买卡券或则担保支付的订单，不支持实时清算.bizSceneType:<{}>", bizScene);
            return AppParamConstant.NO;
        }
        /* 获取法人行实时清算配置参数 */
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(instId, ShareParamConstant.MCHNT_SERVICE, ShareParamConstant.ALLOW_MCHNT_D0_SETTLE_INST);
        if (null == sysParam || !AppParamConstant.YES.equals(sysParam.getParamValue())) {
            rglog.debug("当前机构<{}>未打开商户实时清算开关,不支持商户实时入账...", instId);
            return AppParamConstant.NO;
        }
        sysParam = sysParamService.getSysParamInfo(instId, ShareParamConstant.MCHNT_SERVICE, ShareParamConstant.D0_ACCOUNTING_MIN_AMT);
        String minRealSettleAmt = (null == sysParam) ? ShareParamConstant.DEFAULT_D0_ACCOUNTING_MIN_AMT : sysParam.getParamValue();
        if (AmountUtil.compare(realSettleAmt, minRealSettleAmt) == -1) {
            rglog.debug("商户清算本金<{}>小于商户实时入账最低限制金额<{}>，不实时入账", realSettleAmt, minRealSettleAmt);
            return AppParamConstant.NO;
        }
        /* 获取商户费率信息 */
        List<MchntFeeInfo> mchntFeeInfoList = getMchntFeeInfo(instId, mchntNo);
        if (null == mchntFeeInfoList || mchntFeeInfoList.isEmpty()) {
            rglog.info("未查询到当前商户费率信息,不支持实时清算，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return AppParamConstant.NO;
        }
        Optional<MchntFeeInfo> mchntFeeInfoOpt = mchntFeeInfoList.stream().filter(item ->
                item.getFeeInputMode().equals("0") && DateUtil.compareDate(item.getFeeEffectiveDate(), DateUtil.getCurrentDate()) >= 0).findAny();
        if (mchntFeeInfoOpt.isPresent()) {
            rglog.info("当前商户为特殊计费的商户,不支持实时清算，instId:<{}>,mchntNo:<{}>", instId, mchntNo);
            return AppParamConstant.NO;
        }
        /* 获取商户结算账户信息 */
        List<MchntAcctInfo> mchntAcctInfoList = getMchntAcctInfo(instId, mchntNo);
        Optional<MchntAcctInfo> mchntAcctInfoOpt = mchntAcctInfoList.
                stream().filter(item -> item.getBaseProdCode().equals(bizProdCode) && item.getFundType().equals("00")).findFirst();
        if (mchntAcctInfoOpt.isPresent()) {
            MchntAcctInfo mchntAcctInfo = mchntAcctInfoOpt.get();
            if (AcctTypeEnum.BANK_DEBIT.getAcctType().equals(mchntAcctInfo.getSettleAcctType()) ||
                    AcctTypeEnum.BANK_CREDIT.getAcctType().equals(mchntAcctInfo.getSettleAcctType()) ||
                    AcctTypeEnum.BANK_PASSBOOK.getAcctType().equals(mchntAcctInfo.getSettleAcctType()) ||
                    AcctTypeEnum.BANK_ACCT.getAcctType().equals(mchntAcctInfo.getSettleAcctType())) {
                if ("D0".equals(mchntAcctInfo.getSettleType())) {
                    return AppParamConstant.YES;
                } else if (AppParamConstant.YES.equals(mchntInfo.getRealSettleFlag())) {
                    return AppParamConstant.YES;
                } else {
                    return AppParamConstant.NO;
                }
            } else {
                return AppParamConstant.NO;
            }
        } else {
            rglog.debug("当前商户<{}>未配置业务产品代码为<{}>的结算账户配置信息，默认按不实时清算处理!", mchntNo, bizProdCode);
            return AppParamConstant.NO;
        }
    }

    @Override
    public MchntKeyInfo getMchntKeyInfo(String instId, String mchntNo, String mchntAppId, String keyType) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在获取商户<{}>的密钥配置信息,信息获取方式为<{}>", mchntNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
        /* 获取商户费率信息，特殊计费商户不支持商户实时入账 */
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM059");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntKeyInfoQueryRequest mchntKeyInfoQueryRequest = new MchntKeyInfoQueryRequest();
        mchntKeyInfoQueryRequest.setHeader(header);
        mchntKeyInfoQueryRequest.setMchntNo(mchntNo);
        mchntKeyInfoQueryRequest.setMchntAppId(mchntAppId);
        mchntKeyInfoQueryRequest.setKeyType(keyType);
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntKeyInfoQueryResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<MchntKeyInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_KEY_INFO_QUERY_METHOD, mchntKeyInfoQueryRequest);
        } else {
            callResult = (Result<MchntKeyInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_MCHNT_QUERY_SERVICE, ShareServiceConstant.BOMP_MCHNT_KEY_INFO_QUERY_METHOD, mchntKeyInfoQueryRequest);
        }
        if (null == callResult || null == callResult.getResult() || null == callResult.getResult().getMchntKeyInfo()) {
            rglog.error("获取商户密钥配置信息失败，instId:<{}>,mchntNo:<{}>,mchntAppId:<{}>,keyType:<{}>", instId, mchntNo, mchntAppId, keyType);
            return null;
        }
        MchntKeyInfo mchntKeyInfo = new MchntKeyInfo();
        BeanUtil.beanCopy(callResult.getResult().getMchntKeyInfo(), mchntKeyInfo);
        return mchntKeyInfo;
    }

    @Override
    public MchntTermInfo getMchntTermInfo(String instId, String mchntNo, String termNo) throws Exception {
        String mchntTermInfoKey = TransCacheConstant.TERM_INFO + "_" + mchntNo + "_" + termNo;
        MchntTermInfo mchntTermInfo = (MchntTermInfo) GlobalTransUtil.getCacheValue(mchntTermInfoKey);
        if (null == mchntTermInfo) {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
            rglog.info("正在获取商户<{}>下的终端<{}>信息,信息获取方式为<{}>", mchntNo, termNo, "0".equals(callMode) ? "本地调用" : "微服务调用");
            /* 获取商户费率信息，特殊计费商户不支持商户实时入账 */
            Header header = new Header();
            header.setInstId(instId);
            header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
            header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
            header.setTxnNum("M00BM061");
            header.setBizType("00");
            header.setVersion(ShareParamConstant.DUBBO_VSERSION);
            header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
            header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
            header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
            MchntTermInfoQueryRequest mchntTermInfoQueryRequest = new MchntTermInfoQueryRequest();
            mchntTermInfoQueryRequest.setHeader(header);
            mchntTermInfoQueryRequest.setMchntNo(mchntNo);
            mchntTermInfoQueryRequest.setTermNo(termNo);
            DubboService dubboService = new DubboServiceImpl();
            Result<MchntTermInfoQueryResponse> callResult;
            if ("0".equals(callMode)) {
                Class clasz = Class.forName(ShareServiceConstant.BOMP_TERM_MANAGE_SERVICE_INNER_PATH);
                callResult = (Result<MchntTermInfoQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_TERM_INFO_QUERY_METHOD, mchntTermInfoQueryRequest);
            } else {
                callResult = (Result<MchntTermInfoQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_TERM_MANAGE_SERVICE, ShareServiceConstant.BOMP_MCHNT_TERM_INFO_QUERY_METHOD, mchntTermInfoQueryRequest);
            }
            if (null == callResult || null == callResult.getResult() || null == callResult.getResult().getTermInfo()) {
                rglog.error("获取商户终端信息失败，instId:<{}>,mchntNo:<{}>,termNo:<{}>", instId, mchntNo, termNo);
                return null;
            }
            mchntTermInfo = new MchntTermInfo();
            BeanUtil.beanCopy(callResult.getResult().getTermInfo(), mchntTermInfo);
            GlobalTransUtil.setCacheValue(mchntTermInfoKey, mchntTermInfo);
        }
        return mchntTermInfo;
    }

    @Override
    public boolean updateMchntTermInfo(String oprType, MchntTermInfo mchntTermInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
        rglog.info("正在更新商户<{}>下的终端<{}>信息,信息获取方式为<{}>", mchntTermInfo.getMchntNo(), mchntTermInfo.getTermNo(), "0".equals(callMode) ? "本地调用" : "微服务调用");
        /* 获取商户费率信息，特殊计费商户不支持商户实时入账 */
        Header header = new Header();
        header.setInstId(mchntTermInfo.getInstId());
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM062");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(sysSeqNum + RandomUtil.randomNumStr(4));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        MchntTermInfoUpdateRequest mchntTermInfoUpdateRequest = new MchntTermInfoUpdateRequest();
        mchntTermInfoUpdateRequest.setHeader(header);
        mchntTermInfoUpdateRequest.setOprType(oprType);
        TermInfoBean termInfoBean = new TermInfoBean();
        BeanUtil.beanCopy(mchntTermInfo, termInfoBean);
        mchntTermInfoUpdateRequest.setTermInfo(termInfoBean);
        DubboService dubboService = new DubboServiceImpl();
        Result<MchntTermInfoUpdateResponse> callResult;
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_TERM_MANAGE_SERVICE_INNER_PATH);
            callResult = (Result<MchntTermInfoUpdateResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_MCHNT_TERM_INFO_UPDATE_METHOD, mchntTermInfoUpdateRequest);
        } else {
            callResult = (Result<MchntTermInfoUpdateResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_TERM_MANAGE_SERVICE, ShareServiceConstant.BOMP_MCHNT_TERM_INFO_UPDATE_METHOD, mchntTermInfoUpdateRequest);
        }
        if (null == callResult || null == callResult.getResult() || !RespCodeEnum.TRANS_SUCCESS.getRespCode().equals(callResult.getResult().getRespCode())) {
            rglog.error("更新商户终端信息失败，instId:<{}>,mchntNo:<{}>,termNo:<{}>", mchntTermInfo.getInstId(), mchntTermInfo.getMchntNo(), mchntTermInfo.getTermNo());
            return false;
        }
        return true;
    }

    @Override
    public boolean calcMchntFee(List<MchntOrderInfo> mchntOrderInfoList, String feeType) throws Exception {
        if (null == mchntOrderInfoList || mchntOrderInfoList.isEmpty() || null == feeType) {
            rglog.error("商户订单信息或者费率类型为空!");
            return false;
        }
        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
            boolean calcResult = calcMchntFee(mchntOrderInfo, feeType);
            if (!calcResult) {
                rglog.error("计算商户手续费失败,instId:<{}>,mchntNo:<{}>,transAmt:<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo(), mchntOrderInfo.getRealSettleAmt());
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean calcMchntFee(MchntOrderInfo mchntOrderInfo, String feeType) throws Exception {
        if (null == mchntOrderInfo || null == feeType) {
            rglog.error("商户订单信息为空!");
            return false;
        }
        rglog.info("正在计算商户<{}>的商户手续费!", mchntOrderInfo.getMchntNo());
        try {
            CalcMchntFeeBean calcMchntFeeBean = new CalcMchntFeeBean();
            calcMchntFeeBean.setInstId(mchntOrderInfo.getInstId());
            calcMchntFeeBean.setMchntNo(mchntOrderInfo.getMchntNo());
            calcMchntFeeBean.setTransAmt(mchntOrderInfo.getRealSettleAmt());
            calcMchntFeeBean.setIgasBizProdType(mchntOrderInfo.getBizProdCode());
            calcMchntFeeBean.setSubProdType(feeType);
            calcMchntFeeBean.setStageCode(mchntOrderInfo.getProdStageCode());
            calcMchntFeeBean.setStageNum(mchntOrderInfo.getStageNum());
            CalcMchntFee calcMchntFee = new CalcMchntFee();
            CalcMchntFeeResultBean calcMchntFeeResultBean = calcMchntFee.calcPayFee(calcMchntFeeBean);
            if (null != calcMchntFeeResultBean) {
                mchntOrderInfo.setMchntFee(calcMchntFeeResultBean.getMchntFee());
                mchntOrderInfo.setFeeInputMode(calcMchntFeeResultBean.getFeeInputMode());
                mchntOrderInfo.setFeeRate(calcMchntFeeResultBean.getFeeRate());
                mchntOrderInfo.setFeeCappingAmt(calcMchntFeeResultBean.getFeeCappingAmt());
                mchntOrderInfo.setFeeFixedAmt(calcMchntFeeResultBean.getFeeFixedAmt());
                mchntOrderInfo.setMchntSettleAmt(AmountUtil.subtraction(mchntOrderInfo.getRealSettleAmt(), calcMchntFeeResultBean.getMchntFee()));
            } else {
                rglog.error("计算商户手续费失败,instId:<{}>,mchntNo:<{}>,transAmt:<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo(), mchntOrderInfo.getRealSettleAmt());
                return false;
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("计算商户手续费失败:{}", byteArrayOutputStream.toString());
            return false;
        }
        return true;
    }

    @Override
    public boolean calcMchntRefundFee(MchntOrderInfo refundMchntOrderInfo, MchntOrderInfo origMchntOrderInfo) throws Exception {
        rglog.info("正在计算商户退款手续费!");
        try {
            CalcReverseMchntFeeBean calcReverseMchntFeeBean = new CalcReverseMchntFeeBean();
            /* 本次退款金额 */
            calcReverseMchntFeeBean.setTransAmt(refundMchntOrderInfo.getRealSettleAmt());
            /* 累计退款金额 */
            calcReverseMchntFeeBean.setRefundAmt(origMchntOrderInfo.getRefundAmt());
            /* 累计退款手续费 */
            calcReverseMchntFeeBean.setRefundFee(origMchntOrderInfo.getRefundFee());
            /* 原交易金额 */
            calcReverseMchntFeeBean.setOrigTransAmt(origMchntOrderInfo.getRealSettleAmt());
            /* 原交易应收商户手续费 */
            calcReverseMchntFeeBean.setOrigMchntFee(origMchntOrderInfo.getMchntFee());
            /* 费率比率 */
            calcReverseMchntFeeBean.setFeeRate(origMchntOrderInfo.getFeeRate());
            /* 固定金额 */
            calcReverseMchntFeeBean.setFeeFixedAmt(origMchntOrderInfo.getFeeFixedAmt());
            /* 费率输入方式 */
            calcReverseMchntFeeBean.setFeeInputMode(origMchntOrderInfo.getFeeInputMode());
            /* 封顶金额 */
            calcReverseMchntFeeBean.setFeeCappingAmt(origMchntOrderInfo.getFeeCappingAmt());
            CalcMchntFee calcMchntFee = new CalcMchntFee();
            CalcReverseMchntFeeResultBean calcReverseMchntFeeResultBean = calcMchntFee.calcRefendFee(calcReverseMchntFeeBean);
            if (null != calcReverseMchntFeeResultBean) {
                refundMchntOrderInfo.setMchntFee(calcReverseMchntFeeResultBean.getMchntFee());
                refundMchntOrderInfo.setMchntSettleAmt(AmountUtil.subtraction(refundMchntOrderInfo.getRealSettleAmt(), calcReverseMchntFeeResultBean.getMchntFee()));
            } else {
                rglog.error("计算商户退款手续费失败!");
                return false;
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("计算商户退款手续费失败:{}", byteArrayOutputStream.toString());
            return false;
        }
        return true;
    }
}
